package org.bbelovic.devel.exercises.collatz;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;

public class Axis {

    /** application window width */
    private final int width;
    /** application window height */
    private final int height;
    /** x-coordinate of start of coordinate system */
    private final int startX;
    /** y-coordinate of start of coordinate system */
    private final int startY;
    /** number of units on x-axis */
    private final int xScale;
    /** number of units on y-axis */
    private final int yScale;
    
    /** step on x-axis */
    private final int xScaleStep;
    /** step on y-axis */
    private final int yScaleStep;
    private final int padding;

    public Axis(final AxisConfiguration configuration) {
        this.height = configuration.getHeight();
        this.width = configuration.getWidth();
        this.xScale = configuration.getXScale();
        this.yScale = configuration.getYScale();
        this.xScaleStep = configuration.getXScaleStep();
        this.yScaleStep = configuration.getYScaleStep();
        this.padding = configuration.getPadding();
        startX = padding;
        startY = height - padding;
    }

    public static Axis fromConfiguration(final AxisConfiguration configuration) {
        return new Axis(configuration);
    }

    public void drawAxes(Graphics g) {

        final int xstep = (width - 2*padding)/xScale;
        final int ystep = (height - 2*padding)/yScale;

        g.setColor(Color.BLACK);
        drawAxis(g);

        // draws scale on x-axis
        describeAxis(xScale, xstep, 0, xScaleStep, g, true);
        // draws scale on y-axis
        describeAxis(yScale, 0, -ystep, yScaleStep, g, false);

    }

    /**
     * Draws X and Y axis using given {@link Graphics} instance.
     * @param g
     */
    private void drawAxis(final Graphics g) {
        int endX = width - padding;
        int endY = height - padding;
        g.drawLine(this.startX, this.startY, endX, endY);
        endX = padding;
        endY = padding;
        g.drawLine(this.startX, this.startY, endX, endY);
    }

    public void drawPoint(final Point p, final Graphics g) {
        final int xstep = (width - 2*padding)/xScale;
        final int ystep = (height - 2*padding)/yScale;
        int x = (int) ((p.getX()/xScaleStep) * xstep);
        int y = (int) ((p.getY()/yScaleStep) * ystep);
        g.drawRect(startX+x, startY-y, 1, 1);
    }

    public int getWidth() {
        return this.width;
    }

    public int getHeight() {
        return this.height;
    }

    public int getXScale() {
        return this.xScale;
    }

    public int getYScale() {
        return this.yScale;
    }

    public int getStartX() {
        return this.startX;
    }

    public int getStartY() {
        return this.startY;
    }

    private void drawScaleUnits(final int xCoordinate, final int yCoordinate, final Graphics g, final int scaleStep, boolean orientation) {
        final int lineSize = 2;
        final int deltaX = orientation ? 0 : lineSize;
        final int deltaY = orientation ? lineSize : 0;
        g.drawLine(xCoordinate-deltaX, yCoordinate-deltaY, xCoordinate+deltaX, yCoordinate+deltaY);
        g.setColor(Color.BLUE);
        g.drawString(String.valueOf(scaleStep), xCoordinate-8, yCoordinate+15);
    }

    private void describeAxis(int scale, int xStep, int yStep, int scaleStep, Graphics g, boolean orientation) {
        for (int i = 1; i <= scale; i++) {
            drawScaleUnits(this.startX+i*xStep, this.startY+i*yStep, g, i*scaleStep, orientation);
        }
    }
}
